package cn.genmer.test.security.rpc.v2.rpc.transport;

import cn.genmer.test.security.rpc.v2.rpc.protocol.GContent;
import cn.genmer.test.security.rpc.v2.rpc.protocol.GHeader;
import cn.genmer.test.security.rpc.v2.rpc.protocol.GPackmsg;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.util.List;

// 自定义 解码器
public class GCommonDecode extends ByteToMessageDecoder {
    public static int SERVER_FLAG = 0x14141414;
    public static int CLIENT_FLAG = 0x14141424;

    // 父类里一定有chnnelRead{调用decode, 留存部分会自动存到cumulation}-> bytebuf
    // Netty提供了，不然可以自己写
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf buf, List<Object> list) throws Exception {
        // 参数里的buf是【用户空间】开辟的直接内存空间，是内核【系统调用】从【内核空间】读出来的字节数组，拷贝到【用户空间】
        System.out.println("【Server】接收数据大小：" + buf.readableBytes());
        // 124 head大小 - 会根据包路径变更而改变大小，确定发版都不变
        while (buf.readableBytes() >= 124){
            byte[] bytes = new byte[124];
//            buf.readBytes(bytes);
            buf.getBytes(buf.readerIndex(),bytes); // 从哪里读，读多少，不会移动指针（readIndex）
            ByteArrayInputStream in = new ByteArrayInputStream(bytes);
            ObjectInputStream oin = new ObjectInputStream(in);
            GHeader header = (GHeader)oin.readObject();

            // Decode在两个方向（输入、输出）都使用，应该做一个判断
            if (buf.readableBytes()-124 >= header.getDataLength()){
                // 处理指针
                buf.readBytes(124); // 移动指针到body开始的位置
                byte[] data = new byte[(int)header.getDataLength()];
                buf.readBytes(data);
                ByteArrayInputStream din = new ByteArrayInputStream(data);
                ObjectInputStream doin = new ObjectInputStream(din);

                // 服务端Flag
                if (header.getFlag() == SERVER_FLAG) {
                    GContent content = (GContent) doin.readObject();
                    list.add(new GPackmsg(header, content));
                } else if (header.getFlag() == CLIENT_FLAG){
                    GContent content = (GContent) doin.readObject();
                    list.add(new GPackmsg(header, content));
                }
            } else {
              break;
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("【发生异常】连接关闭！" + cause.getMessage());
        super.exceptionCaught(ctx, cause);

        Channel channel = ctx.channel();
        if(channel.isActive())ctx.close();
    }
}